﻿using Microsoft.EntityFrameworkCore;
using Sgr.Domain.Entities;
using Sgr.Domain.Entities.Auditing;
using Sgr.Domain.Repositories;
using Sgr.EntityFrameworkCore;
using Sgr.Exceptions;
using Sgr.Generator;
using Sgr.UPMS.Domain.Roles;

namespace Sgr.UPMS.Infrastructure.Repositories
{
    /// <summary>
    /// 角色仓储实现
    /// </summary>
    /// <remarks>
    /// 实现了角色相关的数据访问操作：
    /// - 角色的基础CRUD操作
    /// - 角色名称唯一性检查
    /// - 角色资源关系维护
    /// </remarks>
    public class RoleRepository<TDbContext>
        : EfCoreRepositoryOfTEntityAndTPrimaryKey<TDbContext, Role, long>, IRoleRepository where TDbContext : UnitOfWorkDbContext
    {
        private readonly ISegmentNumIdGenerator _numberIdGenerator;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dbContextProvider"></param>
        /// <param name="auditedOperator">审计操作者</param>
        /// <param name="numberIdGenerator">数字ID生成器</param>
        /// <exception cref="BusinessException">参数为空时抛出异常</exception>
        public RoleRepository(
            IDbContextProvider<TDbContext> dbContextProvider,
            IAuditedOperator auditedOperator,
            ISegmentNumIdGenerator numberIdGenerator)
            : base(dbContextProvider, auditedOperator)
        {
            _numberIdGenerator = numberIdGenerator ?? throw new ArgumentNullException(nameof(numberIdGenerator));
        }

        /// <summary>
        /// 检查并设置主键Id
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns></returns>
        protected override async Task CheckAndSetIdAsync(Role entity, CancellationToken cancellationToken = default)
        {
            if (entity.Id == 0)
                entity.Id = await _numberIdGenerator.GetUniqueIdAsync(UpmsConstant.DEFAULT_SEGMENT_KEY, cancellationToken);
        }

        /// <summary>
        /// 根据角色ID集合获取对应的资源列表
        /// </summary>
        /// <param name="roleIds"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        /// <exception cref="BusinessException"></exception>
        public async Task<IEnumerable<string>> GetResourcesByRoleIdsAsync(long[] roleIds, CancellationToken cancellationToken = default)
        {
            Check.NotNull(roleIds, nameof(roleIds));

            if (roleIds.Length == 0)
            {
                throw new BusinessException("角色ID集合不能为空");
            }

            // 使用高效的查询方式获取资源
            var dbContext = await GetDbContextAsync(cancellationToken);
            return await dbContext.Set<Role>()
                .AsNoTracking()
                .Where(r => r.State == EntityStates.Normal && roleIds.Contains(r.Id))
                .SelectMany(r => r.Resources.Select(res => res.ResourceCode))
                .Distinct()
                .ToListAsync(cancellationToken);
        }

        /// <summary>
        /// 检查角色名称是否唯一
        /// </summary>
        /// <param name="name">角色名称</param>
        /// <param name="excludedId">需要排除的角色ID（用于编辑场景）</param>
        /// <param name="orgId">组织ID</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>true: 名称唯一; false: 名称已存在</returns>
        /// <exception cref="ArgumentException">当name为空时抛出</exception>
        public async Task<bool> NameIsUniqueAsync(
            string name,
            long? excludedId = null,
            long orgId = 0,
            CancellationToken cancellationToken = default)
        {
            Check.StringNotNullOrEmpty(name, nameof(name));

            // 构建查询
            var dbContext = await GetDbContextAsync(cancellationToken);
            var query = dbContext.Set<Role>()
                .AsNoTracking()
                .Where(x => x.OrgId == orgId && x.RoleName == name);

            // 排除当前记录（用于编辑场景）
            if (excludedId.HasValue && excludedId.Value > 0)
            {
                query = query.Where(x => x.Id != excludedId.Value);
            }

            // 检查是否存在记录
            var exists = await query.AnyAsync(cancellationToken);

            // 返回唯一性检查结果（true表示唯一，即不存在重复记录）
            return !exists;
        }
    }
}